package com.hq.ims.data.service;

import com.baomidou.mybatisplus.annotation.TableName;
import com.hq.ims.data.dao.FileRecordMapper;
import com.hq.ims.data.entity.FileRecord;
import com.hq.ims.data.vo.AppFileMapstruct;
import com.hq.mybatis.base.BaseService;
import com.hq.utils.exception.CommonException;
import com.hq.utils.util.JsonUtils;
import com.hq.utils.util.ListUtils;
import com.hq.utils.util.StringUtils;
import lombok.NonNull;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * jiang bai ping
 *
 * @Email 526666031@qq.com
 * @Detail 全局上传文件服务实现类
 */
@Service
public class BaseFileRecordService extends BaseService<FileRecordMapper, FileRecord> {

    /**
     * @param fileVo                 上传文件
     * @param cls                    类
     * @param ownId                  所属id
     * @param fileMark               文件标记
     * @param isDeleteMarkKeyOldData 是否删除老数据
     * @return : boolean
     * 保存文件
     */
    @Transactional(rollbackFor = Exception.class)
    public <T> boolean saveFile(
            @NonNull AppFileMapstruct.FileVo fileVo,
            @NonNull Class<T> cls,
            @NonNull String ownId,
            @NonNull String fileMark,
            @NonNull boolean isDeleteMarkKeyOldData
    ) {

        TableName annotation = cls.getAnnotation(TableName.class);
        if (annotation == null) {
            throw CommonException.build("类没有标记TableName无法识别");
        }
        //是否需要删除旧的数据
        if (isDeleteMarkKeyOldData) {
            super.lambdaUpdate()
                    .eq(FileRecord::getFileMark, fileMark)
                    .eq(FileRecord::getOwnTableName, annotation.value())
                    .eq(FileRecord::getOwnTableDataId, ownId)
                    .remove();
        }

        FileRecord globalFile = saveAndReturnFile(fileVo, cls, ownId, fileMark);
        return globalFile != null;
    }

    /**
     * @param fileVos                上传文件
     * @param cls                    类
     * @param ownId                  所属id
     * @param fileMark               文件标记
     * @param isDeleteMarkKeyOldData 是否删除老数据
     * @return : boolean
     * 保存文件
     */
    @Transactional(rollbackFor = Exception.class)
    public <T> boolean saveFile(
            @NonNull List<AppFileMapstruct.FileVo> fileVos,
            @NonNull Class<T> cls,
            @NonNull String ownId,
            @NonNull String fileMark,
            @NonNull boolean isDeleteMarkKeyOldData
    ) {
        boolean isSuccess = false;

        TableName annotation = cls.getAnnotation(TableName.class);
        if (annotation == null) {
            throw CommonException.build("类没有标记TableName无法识别");
        }
        //是否需要删除旧的数据
        if (isDeleteMarkKeyOldData) {
            super.lambdaUpdate()
                    .eq(FileRecord::getFileMark, fileMark)
                    .eq(FileRecord::getOwnTableName, annotation.value())
                    .eq(FileRecord::getOwnTableDataId, ownId)
                    .remove();
        }

        if (ListUtils.isExistsEle(fileVos)) {
            List<FileRecord> returnList = new ArrayList<>(fileVos.size());
            fileVos.forEach(fileVo -> {
                FileRecord fileProjectRecord = this.saveAndReturnFile(fileVo, cls, ownId, fileMark);
                returnList.add(fileProjectRecord);
            });
            isSuccess = ListUtils.isExistsEle(returnList);
        }
        return isSuccess;
    }

    /**
     * @param fileVo   上传文件
     * @param cls      类
     * @param ownId    所属id
     * @param fileMark 文件标记
     * @return : com.hq.ce.safety.data.entity.GlobalUploadFile
     * <p>
     * <p>
     * 保存文件
     */
    @Transactional(rollbackFor = Exception.class)
    public <T> FileRecord saveAndReturnFile(
            @NonNull AppFileMapstruct.FileVo fileVo,
            @NonNull Class<T> cls,
            @NonNull String ownId,
            @NonNull String fileMark
    ) {
        FileRecord fileProjectRecord = JsonUtils.convertObject(fileVo, FileRecord.class);
        fileProjectRecord.setFileRecordId(StringUtils.EMPTY);
        fileProjectRecord.setIsDel(false);
        fileProjectRecord.setFileUrl(fileVo.getFileDownloadUrl());
        TableName annotation = cls.getAnnotation(TableName.class);
        if (annotation == null) {
            throw CommonException.build("类没有标记TableName无法识别");
        }
        fileProjectRecord.setOwnTableName(annotation.value());
        fileProjectRecord.setOwnTableDataId(ownId);
        fileProjectRecord.setFileMark(fileMark);
        fileProjectRecord.setDownCount(0);
//        ITokenUserInfo currentUser = AppUtils.getCurrentUser();
//        if (currentUser == null) {
//            throw CommonException.build("无效的用户");
//        }

        boolean insertBoolean = fileProjectRecord.insert();
        if (!insertBoolean) {
            throw CommonException.build();
        }
        return fileProjectRecord;
    }

    /**
     * @param fileId 文件id
     * @return : boolean
     * <p>
     * <p>
     * 删除文件
     */
    @Transactional(rollbackFor = Exception.class)
    public boolean delById(@NonNull String fileId) {
        if (StringUtils.isEmpty(fileId)) {
            throw CommonException.build("ID不能为空");
        }

        FileRecord globalFile = this.getById(fileId);
        return globalFile.deleteById();
    }

    /**
     * @param fileIds 文件ids
     * @return : boolean
     * <p>
     * <p>
     * 删除文件
     */
    @Transactional(rollbackFor = Exception.class)
    public boolean delByFileIdList(@NonNull List<String> fileIds) {
        if (ListUtils.isNotExistsEle(fileIds)) {
            throw CommonException.build("需要删除的文件列表不能为空");
        }

        return this.lambdaUpdate().in(FileRecord::getFileRecordId, fileIds).remove();
    }

    /**
     * @param cls     类
     * @param tableId 所属id
     * @return : boolean
     * <p>
     * <p>
     * 删除文件
     */
    @Transactional(rollbackFor = Exception.class)
    public <T> boolean delFile(@NonNull Class<T> cls, @NonNull String tableId) {
        if (StringUtils.isEmpty(tableId)) {
            throw CommonException.build("ID不能为空");
        }
        TableName annotation = cls.getAnnotation(TableName.class);
        if (annotation == null) {
            throw CommonException.build("类没有标记TableName无法识别");
        }

        return this.delFile(cls, tableId, null);
    }

    /**
     * @param tableId  所属id
     * @param fileMark 文件标记
     * @return : boolean
     * <p>
     * <p>
     * 删除文件
     */
    @Transactional(rollbackFor = Exception.class)
    public boolean delFile(@NonNull String tableId, String fileMark) {
        if (StringUtils.isEmpty(tableId)) {
            throw CommonException.build("ID不能为空");
        }

        return this.delFile(null, tableId, fileMark);
    }

    /**
     * @param cls      类
     * @param tableId  所属id
     * @param fileMark 文件标记
     * @return : boolean
     * <p>
     * <p>
     * 删除文件
     */
    @Transactional(rollbackFor = Exception.class)
    public <T> boolean delFile(Class<T> cls, String tableId, String fileMark) {
        String ownTableName = StringUtils.EMPTY;
        if (cls != null) {
            TableName annotation = cls.getAnnotation(TableName.class);
            ownTableName = annotation.value();
        }

        return super.lambdaUpdate()
                .eq(StringUtils.isNotEmpty(tableId), FileRecord::getOwnTableDataId, tableId)
                .eq(StringUtils.isNotEmpty(ownTableName), FileRecord::getOwnTableName, ownTableName)
                .eq(StringUtils.isNotEmpty(fileMark), FileRecord::getFileMark, fileMark)
                .remove();
    }

    /**
     * @param cls     类
     * @param tableId 所属id
     * @return : java.util.List<com.hq.ce.safety.data.entity.GlobalUploadFile>
     * <p>
     * <p>
     * 获取文件
     */
    @Transactional(rollbackFor = Exception.class)
    public <T> List<FileRecord> getFile(@NonNull Class<T> cls, @NonNull String tableId) {
        if (StringUtils.isEmpty(tableId)) {
            throw CommonException.build("ID不能为空");
        }
        TableName annotation = cls.getAnnotation(TableName.class);
        if (annotation == null) {
            throw CommonException.build("类没有标记TableName无法识别");
        }

        return this.getFile(cls, tableId, null);
    }

    /**
     * @param tableId  所属id
     * @param fileMark 文件标记
     * @return : java.util.List<com.hq.ce.safety.data.entity.GlobalUploadFile>
     * <p>
     * <p>
     * 获取文件
     */
    @Transactional(rollbackFor = Exception.class)
    public <T> List<FileRecord> getFile(@NonNull String tableId, @NonNull String fileMark) {
        if (StringUtils.isEmpty(tableId)) {
            throw CommonException.build("ID不能为空");
        }
        if (StringUtils.isEmpty(fileMark)) {
            throw CommonException.build("fileMark不能为空");
        }

        return this.getFile(null, tableId, fileMark);
    }

    /**
     * @param cls      类
     * @param tableId  所属id
     * @param fileMark 文件标记
     * @return : java.util.List<com.hq.ce.safety.data.entity.GlobalUploadFile>
     * <p>
     * <p>
     * 获取文件
     */
    @Transactional(rollbackFor = Exception.class)
    public <T> List<FileRecord> getFile(Class<T> cls, String tableId, String fileMark) {
        String ownTableName = StringUtils.EMPTY;
        if (cls != null) {
            TableName annotation = cls.getAnnotation(TableName.class);
            ownTableName = annotation.value();
        }

        return super.lambdaQuery()
                .eq(StringUtils.isNotEmpty(tableId), FileRecord::getOwnTableDataId, tableId)
                .eq(StringUtils.isNotEmpty(ownTableName), FileRecord::getOwnTableName, ownTableName)
                .eq(StringUtils.isNotEmpty(fileMark), FileRecord::getFileMark, fileMark)
                .orderByDesc(FileRecord::getCreateDateTime)
                .list();
    }

    /**
     * @param oriId 复制前所属id
     * @param newId 复制后所属id
     * @param cls   类
     * @return : boolean
     * <p>
     * <p>
     * 复制文件
     */
    @Transactional(rollbackFor = Exception.class)
    public <T> boolean copy(@NonNull String oriId, @NonNull String newId, @NonNull Class<T> cls) {
        TableName annotation = cls.getAnnotation(TableName.class);
        //获取要复制的文件
        List<FileRecord> list = this.lambdaQuery().eq(FileRecord::getOwnTableDataId, oriId)
                .list();
        if (ListUtils.isNotExistsEle(list)) {
            return true;
        }
        //删除新id中的文件
        this.delFile(cls, newId);
        for (FileRecord userGlobalFile : list) {
            userGlobalFile.setFileRecordId(null);
            userGlobalFile.setOwnTableDataId(newId);
            userGlobalFile.setOwnTableName(annotation.value());
        }
        this.saveBatch(list);
        return true;
    }

    /**
     * 保存签署文档
     *
     * @param signedDocuments        签署文件
     * @param cls                    cls
     * @param ownId                  自己身份证
     * @param fileMark               文件标志
     * @param isDeleteMarkKeyOldData 是删除旧马克关键数据
     * @return {@code  }
     */
    @Transactional(rollbackFor = Exception.class)
    public <T> boolean saveSignedDocument(
            @NonNull List<String> signedDocuments,
            @NonNull Class<T> cls,
            @NonNull String ownId,
            @NonNull String fileMark,
            @NonNull boolean isDeleteMarkKeyOldData
    ) {
        boolean isSuccess = false;

        TableName annotation = cls.getAnnotation(TableName.class);
        if (annotation == null) {
            throw CommonException.build("类没有标记TableName无法识别");
        }
        //是否需要删除旧的数据
        if (isDeleteMarkKeyOldData) {
            super.lambdaUpdate()
                    .eq(FileRecord::getFileMark, fileMark)
                    .eq(FileRecord::getOwnTableName, annotation.value())
                    .eq(FileRecord::getOwnTableDataId, ownId)
                    .remove();
        }

        if (ListUtils.isExistsEle(signedDocuments)) {
            List<FileRecord> returnList = new ArrayList<>(signedDocuments.size());
            signedDocuments.forEach(signedDocument -> {
                FileRecord fileActivityRecord = new FileRecord();
                returnList.add(fileActivityRecord);
                fileActivityRecord.setFileRecordId(StringUtils.EMPTY);
                fileActivityRecord.setIsDel(false);
                fileActivityRecord.setOwnTableName(annotation.value());
                fileActivityRecord.setOwnTableDataId(ownId);
                fileActivityRecord.setFileMark(fileMark);
                fileActivityRecord.setFileUrl(signedDocument);
                fileActivityRecord.setDownCount(0);
            });
            isSuccess = ListUtils.isExistsEle(returnList);
            this.saveBatch(returnList);
        }
        return isSuccess;
    }

    /**
     * 得到签署文件
     *
     * @param tableId  表id
     * @param fileMark 文件标志
     * @return {@code List<FileProjectRecord> }
     */
    @Transactional(rollbackFor = Exception.class)
    public <T> List<String> getSignedDocument(String tableId, String fileMark) {
        List<FileRecord> list = super.lambdaQuery()
                .eq(StringUtils.isNotEmpty(tableId), FileRecord::getOwnTableDataId, tableId)
                .eq(StringUtils.isNotEmpty(fileMark), FileRecord::getFileMark, fileMark)
                .orderByDesc(FileRecord::getCreateDateTime)
                .list();
        if (ListUtils.isNotExistsEle(list)) {
            return null;
        }
        return list.stream().map(FileRecord::getFileUrl).distinct().collect(Collectors.toList());
    }


    public InputStream convertInputStream(String base64Img) {
        if (base64Img.contains(",")) {
            base64Img = base64Img.split(",")[1];
        }
        return new ByteArrayInputStream(org.apache.commons.codec.binary.Base64.decodeBase64(base64Img));
    }

    /**
     * 预览地址
     */
    String PREVIEW_URL_FORM_STR = "/global/base/app/preview?fileId=%s";

    public List<AppFileMapstruct.FileVo> changeFileRecordToFileVo(List<FileRecord> fileRecords) {

        List<AppFileMapstruct.FileVo> fileVos = new ArrayList<>();

        for (FileRecord fileRecord : fileRecords) {
            AppFileMapstruct.FileVo fileVo = JsonUtils.convertObject(fileRecord, AppFileMapstruct.FileVo.class);
            fileVo.setFileDownloadUrl(fileRecord.getFileUrl());
            fileVo.setFilePreviewUrl(String.format(PREVIEW_URL_FORM_STR, fileRecord.getFileId()));
            fileVos.add(fileVo);
        }
        return fileVos;
    }


}
